Parallax-Scrolling

← Zurück zum Forum

Ich beschäftige mich gerade mit Parallax-Scrolling und da es im neuen und alten Forum keine ausreichende Diskussion darüber gibt, möchte ich es hier gerne öffentlich diskutieren. Am Ende soll ein relativ einfacher aber nachvollziehbarer Assembler-Code rauskommen, den jeder in sein mögliches Programm einbauen bzw. anpassen /erweitern kann.

AntwortZitat

... mein Beispielcode ist nun fertig und ich werde das hier jetzt Schritt für Schritt posten und erklären! Folgende Kriterien sollte der Code haben:

  1. Da ich mein nächstes Spiel wohl im Antic-Modus D erstellen werde (Bitmap 160x96, 4 Farben) sollte die Displaylist auch entsprechend für dieses Beispiel aufgebaut werden.
  2. Da ich mehr als 4 Farben reinbringen möchte, sollte die Displaylist entsprechend mit 3 Displaylist-Interrupts manipuliert werden.
  3. Der Code sollte einfach und kurz sein. Ich wollte den Code so machen, daß alles gut lesbar drin ist (keine Includes...).
  4. Der Code sollte nur ein einfaches Feinscrolling in drei unterschiedlichen Geschwindigkeiten darstellen, auf ein Grobscroll habe ich hier extra verzichtet - ein Grobscroll kann ich gerne später noch in den Code integrieren wenn erwünscht.

Vorab der komplette Code hier, den ich später pö a pö erkläre - gleich ruft aber erstmal die Sonne und der Garten 😉

    org $1000   

screen = 240
scrolm1 = 242
scrolm2 = 243
scrolm3 = 244
scrolindex =245
delay = 246   

VDSLST = 512
NMIEN = 54286
wsync = 54282
hscrol = 54276
rtclok = 18
colpf1 = 53271



      .proc main

      mwa #dlist1 560

      lda #<dli0
      sta VDSLST
      lda #>dli0
      sta VDSLST+1
      lda #192
      sta NMIEN
      ldy #0
      lda #0 
      sta 710
      lda #15
      sta scrolm1
      sta scrolm2
      sta scrolm3

main2   
      ldx #0
      mva #$a0 screen+1
      mva #$4f screen
@     lda #170
      sta (screen),y
      clc
      lda screen
      adc #48
      sta screen
      lda screen+1
      adc #0
      sta screen+1
      clc
      inx
      cpx #90
      bne @-

loop    ldx #15
      clc
@   
      inc scrolindex
      dec scrolm3
      mva #2 delay
      jsr wartes
      dec scrolm3
      dec scrolm2
      mva #2 delay
      jsr wartes
      dec scrolm1
      dec scrolm2
      dec scrolm3
      mva #2 delay
      jsr wartes

      #if .byte scrolm1<=#1
      mva #15 scrolm1
      #end
      #if .byte scrolm2<=#1
      mva #15 scrolm2
      #end
      #if .byte scrolm3<=#1
      mva #15 scrolm3
      #end

      dex
      stx 250
      clc
      ldx 250
      cpx #1
      bne @-
      jmp loop

      .endp



      ; ---------------------------- S U B R O U T I N E N ----------------------------------

      .proc wartes
      clc
        ldx delay ; Warteschleife
st      
      lda RTCLOK+2

wa   
      cmp RTCLOK+2 
          beq wa 
          dex            
          bpl st 
          rts
     .endp   
      .proc dlist1
      .by 112,112,112,93  ;64+13+16
      .by 40,160,29 
      .by 29
      .by 157
:19     .by 29
      .by 157
:33     .by 29
      .by 29
:27     .by 29
      .by 157
      .by 65
      .wo dlist1
      .endp
      .proc dli0
        phr
        sta wsync
        mva #55 colpf1
        mva scrolm2 hscrol
        sta wsync
        mwa #dli1 512
        plr
        rti
      .endp
      .proc dli1
        phr
        sty wsync
        mva scrolm3 hscrol
        mva #111 colpf1 
        sta wsync
        mwa #dli2 512
        plr
        rti
      .endp
      .proc dli2
        phr
        sta wsync
        mva scrolm1 hscrol
        mva #222 colpf1
        sta wsync
        mwa #dli0 512
        plr
        rti
      .endp
AntwortZitat

... ich bin noch dabei in meine Routine das Grobscroll einzubauen, dabei gab es nun doch mehr Probleme als ich gedacht hatte. Das Timing ist nicht so einfach und einen 4k Bildschirm im DLI zu bewegen geht nicht. Das kostet zu viel Zeit. Im VBI ist das eher möglich in Portionen, flackert aber.

Ich versuche das Grobscroll nun durch Displaylist-Manipulation zu realisieren, es gibt da ein paar Vorlagen, die ich aber verdammt kompliziert finde. Das versuche ich jetzt selber zu basteln und habe da einen ganz guten Ansatz, der für eine Zeile schon zu funktionieren scheint. Nun will ich das noch so anpassen, daß das auch für den gesamten Bildschirm funktioniert...

AntwortZitat

Du musst doch eigentlich nur die Startadresse im DL ändern und nicht den Bildschirm scrollen.

Also quasi so: Der Bildschirm ist eine Lupe, die Du über die Zeitung schiebst... Dabei bleibt die Zeitung liegen.

In jeder Zeile machst Du einen LMS und musst dann nur diese Adresse anpassen. Die Daten müssen dann natürlich auch gut im Speicher liegen. Nehmen wir an, Du hast einen Level, der 3 normale Bildschirme breit ist, dann hast Du also 3*40 Bytes je Zeile und so lautet die DL in etwa so:

     .he 4d
chg  .wo screen
     .he 4d
chg1 .wo screen+120
     .he 4d
chg2 .wo screen+240

Wenn einmal fine scroll durch ist, müssen nun die ganzen chg Werte um ein Byte angepasst werden, bzw. bei hoch oder runter um 120 Bytes.

Hoffe, das ist so zu verstehen.

PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo

AntwortZitat

Hallo und vielen Dank, den Code von dir schaue ich gleich mal an... Ich denke mein Ansatz war wohl ganz ähnlich:

    org $1000

    icl '../hardware.txt'

delay = 240 
var1 = 241

    .proc main

    mwa #dlist1 560


loop  lda random
    sta 39976+79
    ldx #80
@   txa
    sta dlist1+10
    sta var1
    lda random
    sta 39976,x
    sta 39976,x-40
    mva #4 delay
    jsr wartes
    ldx var1
    clc
    inx
    cpx #120
    bne @-
    lda #80
    sta dlist1+10
    jmp loop

    .endp

  ;---------- Subroutinen ---------

    .proc dlist1
dlist .by 117,117,117
    .by 66,0,156    ; 39976
    .by 66,40,156
    .by 66,80,156
    .by 66,160,156
:20   .by 2
    .by 65
    .wo dlist

    rts

    .endp

    .proc wartes
      clc
        ldx delay ; Warteschleife
st      
      lda RTCLOK+2
wa   
      cmp RTCLOK+2 
          beq wa 
          dex            
          bpl st 
          rts
     .endp   


    run main

Das scrollt erstmal nur eine Zeile. Die Zeilenblöcke müssen ja bei Parallax unterschiedlich den Grobscroll ausführen können. Zusätzlich geht es aber meines Erachtens nicht einfach nur wie von dir beschrieben wie mit einer Lupe über die Speicherstellen zu schauen, denn der Scroll geht ja zB von rechts nach links und alles was links aus dem Bildschirm rausscrollt verschwindet und rechts zB kommt etwas neues (Landschaft) rein. Geht man einfach nur über den Speicherbereich, dann ist man zu schnell am Speicherende!

AntwortZitat

Ja, das mit "Lupe über Zeitung"-Scrolling hat den Nachteil, dass die Zeitung komplett fertig daliegen muss und somit Platz benötigt. Man kann mit etwas mehr Aufwand immer nur rechts ein Zeichen mehr haben und in einem zweiten Screen alles um 1 Byte nach links verschoben haben. Dann muss der gesamte Bildschirm umgeschaltet werden, wenn dann alles dorthin kopiert worden ist. Bei Bitmap Grafik aber imho eher zu viel Kopierarbeit.

Irgendwo hatte aber mal jemand die Methode vom Gameboy erklärt. Dort scrollt man auch irgendwie mit der Lupe, aber nur über 2 Bildschirmbreiten. Was links raus geht, bekommt irgendwas von rechts reinkopiert, bis dann ganz rechts angekommen, das selbe im linken Bereich drin ist, dann wird direkt dorthin zurückgesprungen und wieder nach dem Muster neu begonnen. So ganz habe ich das noch nicht geschnallt und weiß gerade nicht mehr, wo ich das gelesen hatte... Eigentlich wollte ich mir den Link speichern - naja, habe ich dann wohl nicht getan 🙄

Hmmm vielleicht ja so...

1,2,3..40,41 Ausgangslage 41,2,3..41,42 erstes Zeichen links raus (also da, wo vorher die 1 war, kommt auch das 41. Zeichen hin, aber der Bildschirm beginnt nun bei 2) 41,42,3..42,43 zweites Zeichen links raus (da wo, die 2 war kommt auch das 42. Zeichen hin, BS beginnt bei 3)

Und wenn dann 40 raus ist, steht ja 41 bis 80 auch dort, wo vorher 1 bis 40 stand, also wird dann mit dem LMS wieder an den Anfang verzweigt und das 81. Byte kommt als nächstes dann an die Stelle, wo anfangs das 41. Byte stand.

Auf diese Weise muss man die LMS in der DL aktualisieren und 2 mal in den Speicher jeweils das eine Byte je Zeile kopieren. Bei 200 Zeilen also 400 Bytes kopieren plus 200 LMS Words aktualisieren. Das könnte schon noch klappen.

Aber irgendwoher muss der Level ja auch kommen. Wenn er dort in "komprimierter" Form ist, wird es sicherlich auch ordentlich Hirnschmalz kosten, das zu dekodieren.

PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo

AntwortZitat

... ganz genau ... schau dir bitte mal meinen letzten Code an. Da habe ich es bereits für eine Zeile recht einfach realisiert. Rechts kommt per Random immer ein neues Zeichen rein und das gescrollte Zeichen wird zwischengespeichert. Daher braucht man einen doppelten Speicherbereich. Nach 40 Grobscroll schaltet man wieder zurück wo aber die aktuelle Zeile (als Doppel) liegt und dann gehts wieder erneut los.... Noch habe ich aber Probleme mit mehreren Zeilen... das bekommt man aber hin!

AntwortZitat

... den Code auf mehrere Zeilen zu erweitern (am Ende soll ja der ganze Bildschirm via Displaylist-Manipulation scrollen) war nicht so ganz einfach, jetzt habe ich es aber geschafft die ersten drei Zeilen zu scrollen - und damit ist auch die Logik für die anderen Zeilen klar!

Anbei der Code:

    org $1000


    icl '../hardware.txt'

delay = 240 
var1 = 241



    .proc main

    mwa #dlist1 560


loop  


    ldx #00

@   txa
    sta dlist1+7
    sta var1
    lda random
    sta 39936,x+39
    sta 39936,x-1
    txa
    adc #80
    sta dlist1+10
    lda random
    sta 40016,x+39
    sta 40016,x-1
    txa
    sta dlist1+13
    lda random
    sta 40192,x+39
    sta 40192,x-1


    mva #6 delay
    jsr wartes
    ldx var1
    clc
    inx
    cpx #40
    bne @-

    lda #0
    sta dlist1+7
    sta dlist1+10
    sta dlist1+13

    jmp loop



    .endp

  ;---------- Subroutinen ---------

    .proc dlist1

dlist .by 117,117,117
    .by 66,0,156    ; 39976
    .by 66,80,156
    .by 66,160,156

    .by 66,0,157
    .by 66,80,157
    .by 66,160,157

    .by 66,0,158
    .by 66,80,158
    .by 66,160,158  

    .by 66,0,159
    .by 66,80,159
    .by 66,160,159  

    .by 66,0,160    ; 39976
    .by 66,80,160
    .by 66,160,160

    .by 66,0,161
    .by 66,80,161
    .by 66,160,161

    .by 66,0,162
    .by 66,80,162
    .by 66,160,162

    .by 66,0,163
    .by 66,80,163
    .by 66,160,163

    .by 65
    .wo dlist

    rts

    .endp

    .proc wartes
      clc
        ldx delay ; Warteschleife
st      
      lda RTCLOK+2

wa   
      cmp RTCLOK+2 
          beq wa 
          dex            
          bpl st 
          rts
     .endp   




    run main

Damit scrollt man jetzt via Displaylist, das Zeichen links fliegt immer raus und rechts schiebe ich ein neues Zeichen wieder rein (hier im Beispiel per Random). Damit kann man den Horizontalshooter laufen lassen - man muss das natürlich entsprechend noch mit dem Feinscroll verbinden.

Gruß Peter

AntwortZitat

... ich habe die ganze Zeit mir meine grauen Zellen zermartert, warum es nicht logisch mit den Zeilen so klappt, wie ich es erwartet habe... und ein wenig rumprobiert. Fakt scheint zu sein: Wenn man jede Zeile mit einer eigenen Adresse definiert, dann muss man die erste Zeile anders behandeln. Der erste 64+2 Befehl definiert ja normalerweise die erste Zeile (Antic 2 zB) mit dem Wert des Startes der Bildschirmadresse. Vorher kommen die 3 x 117 für den Overscan. Jetzt aber definiert der ersten Wert den Start des Overscans... also habe ich dafür einfach einen zusätzlichen Befehl eingeführt, den er jetzt für den Start des Overscans nimmt. Puh... ganz schön kompliziert und unerwartet. Habe ich da irgendwie einen Denkfehler, oder muss das so sein? Die Profis hier können das sicherlich ganz einfach erklären.... so geht es jetzt aber und anbei der korrekte Code mit dem Grobscroll der ersten drei Zeilen bei Antic 2. Ich werde jetzt noch in den nächsten Tagen den Code etwas schlanker und für den ganzen Bildschirmbereich machen - danach übertrage ich das dann auf mein Parallax-Beispiel, denn hier wird es zwingend benötigt!

Der Code:

        org $1000


    icl '../hardware.txt'

delay = 240 
var1 = 241



    .proc main

    mwa #dlist1 560


loop  

    ldx #0
@   txa
    sta dlist1+7
    sta var1
    lda random
    sta 39936,x+39
    sta 39936,x-1
    txa
    adc #80
    sta dlist1+10
    lda random
    sta 40016,x+39
    sta 40016,x-1
    txa
    adc #160
    sta dlist1+13
    lda random
    sta 40096,x+39
    sta 40096,x-1


    mva #6 delay
    jsr wartes
    ldx var1
    clc
    inx
    cpx #40
    bne @-

    lda #0
    sta dlist1+7
    sta dlist1+10
    sta dlist1+13

    jmp loop



    .endp

  ;---------- Subroutinen ---------

    .proc dlist1

dlist .by 117,117,117
    .by 66,210,155
    .by 66,0,156    
    .by 66,80,156
    .by 66,160,156

    .by 66,0,157
    .by 66,80,157
    .by 66,160,157

    .by 66,0,158
    .by 66,80,158
    .by 66,160,158  

    .by 66,0,159
    .by 66,80,159
    .by 66,160,159  

    .by 66,0,160    
    .by 66,80,160
    .by 66,160,160

    .by 66,0,161
    .by 66,80,161
    .by 66,160,161

    .by 66,0,162
    .by 66,80,162
    .by 66,160,162

    .by 66,0,163
    .by 66,80,163
    .by 66,160,163

    .by 65
    .wo dlist

    rts

    .endp

    .proc wartes
      clc
        ldx delay ; Warteschleife
st      
      lda RTCLOK+2

wa   
      cmp RTCLOK+2 
          beq wa 
          dex            
          bpl st 
          rts
     .endp   




    run main

Interessiert das hier überhaupt, oder ist das etwas zu spezielles... immerhin wird man damit relativ einfach und vor allem ohne großen Rechenaufwand ein Grobscroll horizontal ausführen können, wo man eben nicht nur wie mit einer Lupe über den Speicher schaut...

AntwortZitat

hier der Code für den gesamten Bildschirm! Mit delay kann man die Geschwindigkeit verändern. Ich habe den Code extra zum Verständnis so hier mal gepostet, damit jeder gut nachvollziehen kann, wie er aufgebaut ist. In der Praxis wird man allerdings mit einer Matrix arbeiten und so den ganzen Code verschlanken und weniger redundant machen. Der Speicherbedarf beträgt ca. 2KB also etwas mehr als doppelt so viel wie ein Bildschirm Antic 2. Jede Zeile kann extra und eigenständig grobgescrollt werden. Für Antic 2 braucht man also 24 Zeilen (entsprechend Befehlsblöcke) und für Antic D dann 100 Zeilen.

    org $1000


    icl '../hardware.txt'

delay = 240 
var1 = 241


    .proc main

    mwa #dlist1 560

loop  

    ldx #0
@   txa
    sta dlist1+7
    sta var1
    lda random
    sta 256*156,x+39
    sta 256*156,x-1
    txa
    adc #80
    sta dlist1+10
    lda random
    sta 256*156+80,x+39
    sta 256*156+80,x-1
    txa
    adc #160
    sta dlist1+13
    lda random
    sta 256*156+160,x+39
    sta 256*156+160,x-1
    txa
    sta dlist1+16
    lda random
    sta 256*157,x+39
    sta 256*157,x-1
    txa
    adc #80
    sta dlist1+19
    lda random
    sta 256*157+80,x+39
    sta 256*157+80,x-1
    txa
    adc #160
    sta dlist1+22
    lda random
    sta 256*157+160,x+39
    sta 256*157+160,x-1
    txa
    sta dlist1+25
    lda random
    sta 256*158,x+39
    sta 256*158,x-1
    txa
    adc #80
    sta dlist1+28
    lda random
    sta 256*158+80,x+39
    sta 256*158+80,x-1
    txa
    adc #160
    sta dlist1+31
    lda random
    sta 256*158+160,x+39
    sta 256*158+160,x-1
    txa
    sta dlist1+34
    lda random
    sta 256*159,x+39
    sta 256*159,x-1
    txa
    adc #80
    sta dlist1+37
    lda random
    sta 256*159+80,x+39
    sta 256*159+80,x-1
    txa
    adc #160
    sta dlist1+40
    lda random
    sta 256*159+160,x+39
    sta 256*159+160,x-1
    txa
    sta dlist1+43
    sta var1
    lda random
    sta 256*160,x+39
    sta 256*160,x-1
    txa
    adc #80
    sta dlist1+46
    lda random
    sta 256*160+80,x+39
    sta 256*160+80,x-1
    txa
    adc #160
    sta dlist1+49
    lda random
    sta 256*160+160,x+39
    sta 256*160+160,x-1
    txa
    sta dlist1+52
    lda random
    sta 256*161,x+39
    sta 256*161,x-1
    txa
    adc #80
    sta dlist1+55
    lda random
    sta 256*161+80,x+39
    sta 256*161+80,x-1
    txa
    adc #160
    sta dlist1+58
    lda random
    sta 256*161+160,x+39
    sta 256*161+160,x-1
    txa
    sta dlist1+61
    lda random
    sta 256*162,x+39
    sta 256*162,x-1
    txa
    adc #80
    sta dlist1+64
    lda random
    sta 256*162+80,x+39
    sta 256*162+80,x-1
    txa
    adc #160
    sta dlist1+67
    lda random
    sta 256*162+160,x+39
    sta 256*162+160,x-1
    txa
    sta dlist1+70
    lda random
    sta 256*163,x+39
    sta 256*163,x-1
    txa
    adc #80
    sta dlist1+73
    lda random
    sta 256*163+80,x+39
    sta 256*163+80,x-1
    txa
    adc #160
    sta dlist1+76
    lda random
    sta 256*163+160,x+39
    sta 256*163+160,x-1

    mva #1 delay
    jsr wartes
    ldx var1
    clc
    inx
    cpx #40
    bne @+

    jmp loop

@   jmp @-

    .endp

  ;---------- Subroutinen ---------

    .proc dlist1

dlist .by 117,117,117
    .by 66,210,155
    .by 66,0,156    
    .by 66,80,156
    .by 66,160,156

    .by 66,0,157
    .by 66,80,157
    .by 66,160,157

    .by 66,0,158
    .by 66,80,158
    .by 66,160,158  

    .by 66,0,159
    .by 66,80,159
    .by 66,160,159  

    .by 66,0,160    
    .by 66,80,160
    .by 66,160,160

    .by 66,0,161
    .by 66,80,161
    .by 66,160,161

    .by 66,0,162
    .by 66,80,162
    .by 66,160,162

    .by 66,0,163
    .by 66,80,163
    .by 66,160,163

    .by 65
    .wo dlist

    rts

    .endp

    .proc wartes
      clc
        ldx delay ; Warteschleife
st      
      lda RTCLOK+2

wa   
      cmp RTCLOK+2 
          beq wa 
          dex            
          bpl st 
          rts
     .endp   




    run main

AntwortZitat

Jetzt habe ich das mal erweitert und auf Antic D umgeschrieben... wir packen jetzt also 4kB an und machen damit über den gesamten Bildschirm von rechts nach links Grobscroll mittels Displaylistmanipulation.

Drei kurze .mov Beispiele mit unterschiedlichen Delays ... beim letzten habe ich die Warteschleife komplett rausgenommen und man sieht nur noch ein Pixelflimmern, da es einfach zu schnell ist. Im Grunde scrollt man jetzt fast ohne Zeitverzögerung was bei einer Auflösung von 4 kB für den Atari echt enorm ist. Man benötigt natürlich den doppelten Speicher - also 8 kB und ein wenig Code.

Mit dieser Technik werde ich jetzt auch das Parallaxing weiter bauen...

delay3.mov

delay2.mov

delay1.mov

Anhänge:
AntwortZitat

Ich verfolge dein "Entwicklungs-Tagebuch" hier sehr gespannt. (auch wenn ich nicht immer alles so nachvollziehen kann. Lustigerweise wollte ich die letzten Tage immer mal anfragen, ob du kleine Filmchen deiner Programmier-Fortschritte einstellen kannst um das besser nachvollziehen zu können.

Also bitte weiter posten und gerne immer mal wieder mit einem Filmchen aufhübschen. 😉

Ich bin wirklich beeindruckt, wie schnell Du vorankommst. Ich bin ja gerade selbst dabei, mich in die Assembler Programmierung einzuarbeiten. Vor einer Woche habe ich selbst mit dem Thema Scrolling begonnen, nachdem ich mich in die Display List und den DLI eingetüftelt hatte. ... und ich habe nach fünf Tagen gerade mal ein gegenläufiges horizontales Softscrolling hinbekommen:

https://1drv.ms/v/s!AubfF7Hbqd6zku8_0O9vQiSR6YFikQ

AntwortZitat

... ich habe den Code jetzt gerade ein wenig umgeschrieben und angepasst. Die Bildschirmspeicherung erfolgt jetzt indirekt indiziert und hierfür stelle ich 6 Variablen im Bereich Page 0 bereit. 6 Variablen deshalb, weil ich immer 3 Zeilen manipuliere - dabei brauche ich aber die doppele Anzahl weil ich die Zeichen in 2 Speicherbereiche ablege (um 40 versetzt). Alle drei Zeilen kommt dann eine Schleife und mit diesem Code kann ich 81 Zeilen ganz bequem scrollen. Warum nicht 100 Zeilen? Weil ich ja die Displaylist verbiege und das hier mit dem Befehl sta dlist1,x mache (weil es einfach ist) -> 27x9+7=250 .... da ist für x erstmal Schluss. Die letzten Zeilen muss man separat machen, oder die Variable für die Displaylist anders handhaben was natürlich geht... Wer Lust hat, kann den Code bzw. die Idee auch noch viel besser und intelligenter umsetzen...

Für den Parallax brauche ich nun folgendes: Das Feinscroll habe ich ja in drei Bereiche mit unterschiedlicher Geschwindigkeit getrennt, entsprechend muss auch der Grobscroll getrennt werden (den ich dann immer nach 8x Feinscroll aufrufe). Ich werde also drei Subroutinen erstellen: Grobscroll1..2..3 Zu dem Grobscroll kommt dann noch ein kleiner erster Landschaftsbereich dazu (statt Random), damit man auch was erkennen kann.

All das entwerfe ich so, daß ich das später in mein neues Spiel einbauen kann... ... das wird aber noch dauern, denn am Sa. fahre ich mal "kurz" nach Lyon rüber und schaue mir das Konzert von Rammstein an 😉

      org $1000


    icl '../hardware.txt'

zeilen = 230    
delay = 232
var1 = 233
var0 = 234
var80 = 236
var160 = 238    
var20 = 240
var280 = 242
var260 = 244  

    .proc main

    mwa #dlist1 560

loop  
    mva #0 zeilen
    lda #156 
    sta var0+1
    sta var80+1
    sta var160+1
    sta var20+1
    sta var280+1
    sta var260+1
    mva #0 var0
    mva #80 var80
    mva #160 var160
    mva #39 var20     ;0+39
    mva #119 var280     ;80+39
    mva #199 var260     ;160+39
    mva #0 zeilen

    ldy #1
    ldx #7

@   tya
    sta dlist1,x
    sta var1
    lda random
    sta (var20),y
    dey
    sta (var0),y
    iny
    inx
    inx
    inx
    tya
    adc #80
    sta dlist1,x
    lda random
    sta (var280),y
    dey
    sta (var80),y
    iny
    inx
    inx
    inx
    tya
    adc #160
    sta dlist1,x
    lda random
    sta (var260),y
    dey
    sta (var160),y
    iny
    inx
    inx
    inx
    stx var1

    inc var0+1
    inc var80+1
    inc var160+1
    inc var20+1
    inc var280+1
    inc var260+1

    clc
    inc zeilen
    #if .byte zeilen<#27    ; es werden 81 Zeilen grobgescrollt
    jmp @-
    #end

    mva #0 delay
    jsr wartes
    ldx var1
    clc
    iny
    cpy #41
    bne @+

    jmp loop

@   ldx#7
    mva #0 zeilen
    lda #156 
    sta var0+1
    sta var80+1
    sta var160+1
    sta var20+1
    sta var280+1
    sta var260+1

    jmp @-1

    .endp

  ;---------- Subroutinen ---------

    .proc dlist1

dlist .by 117,117,117
    .by 77,210,155
    .by 77,0,156    
    .by 77,80,156
    .by 77,160,156

    .by 77,0,157
    .by 77,80,157
    .by 77,160,157

    .by 77,0,158
    .by 77,80,158
    .by 77,160,158  

    .by 77,0,159
    .by 77,80,159
    .by 77,160,159  

    .by 77,0,160    
    .by 77,80,160
    .by 77,160,160

    .by 77,0,161
    .by 77,80,161
    .by 77,160,161

    .by 77,0,162
    .by 77,80,162
    .by 77,160,162

    .by 77,0,163
    .by 77,80,163
    .by 77,160,163

    .by 77,0,164    
    .by 77,80,164
    .by 77,160,164

    .by 77,0,165
    .by 77,80,165
    .by 77,160,165

    .by 77,0,166
    .by 77,80,166
    .by 77,160,166  

    .by 77,0,167
    .by 77,80,167
    .by 77,160,167

    .by 77,0,168  
    .by 77,80,168
    .by 77,160,168

    .by 77,0,169
    .by 77,80,169
    .by 77,160,169

    .by 77,0,170
    .by 77,80,170
    .by 77,160,170

    .by 77,0,171
    .by 77,80,171
    .by 77,160,171

    .by 77,0,172
    .by 77,80,172
    .by 77,160,172

    .by 77,0,173
    .by 77,80,173
    .by 77,160,173

    .by 77,0,174
    .by 77,80,174
    .by 77,160,174

    .by 77,0,175
    .by 77,80,175
    .by 77,160,175

    .by 77,0,176  
    .by 77,80,176
    .by 77,160,176

    .by 77,0,177
    .by 77,80,177
    .by 77,160,177

    .by 77,0,178
    .by 77,80,178
    .by 77,160,178

    .by 77,0,179
    .by 77,80,179
    .by 77,160,179

    .by 77,0,180  
    .by 77,80,180
    .by 77,160,180

    .by 77,0,181
    .by 77,80,181
    .by 77,160,181

    .by 77,0,182
    .by 77,80,182
    .by 77,160,182

    .by 77,0,183
    .by 77,80,183
    .by 77,160,183

    .by 77,0,184
    .by 77,80,184
    .by 77,160,184

    .by 77,0,185
    .by 77,80,185
    .by 77,160,185

    .by 77,0,186
    .by 77,80,186
    .by 77,160,186

    .by 77,0,187
    .by 77,80,187
    .by 77,160,187



    .by 65
    .wo dlist

    rts

    .endp

    .proc wartes
      clc
        ldx delay ; Warteschleife
st      
      lda RTCLOK+2

wa   
      cmp RTCLOK+2 
          beq wa 
          dex            
          bpl st 
          rts
     .endp   




    run main

AntwortZitat

Hey Olix, vielen Dank! Das sieht schon echt super aus bei dir!!! So weit war ich vor einem Jahr noch lange nicht!! Vieles geht einfacher und schneller mit Eclipse/WUDSN/Mads... das kann ich immer wieder nur so sagen! Ich zeige es dir auf der Fujiama! gruß Peter

AntwortZitat

Prodehl schrieb: Vieles geht einfacher und schneller mit Eclipse/WUDSN/Mads... das kann ich immer wieder nur so sagen! Ich zeige es dir auf der Fujiama!

... super, da freue ich mich drauf.

Bis dahin bin ich mit meiner oldschool Entwicklungsumgebung aber noch ganz zufrieden. Noch macht mir das so Spaß und meine Übungsprogramme sind ja noch überschaubar.

Ich finde es zum lernen sogar produktiver, wenn man nicht zu viel Arbeit von der Entwicklungsumgebung abgenommen bekommt. Zumindest bei mir fördert das, das Verständnis der Vorgänge.

Aber wenn die Programme mal länger und die Aufgaben kniffeliger werden, so wie bei Dir, dann wollte ich auch nicht mehr im Windows-Editor schreiben und den Code dann per Copy-Paste in den Altirra übertragen. 😁

Und dann mal viel Spaß in Lyon mit Rammstein und einem Gläschen französischem Rotwein.

AntwortZitat

... die Arbeit frisst mich gerade auf, da wir Coronafälle bei uns haben und ich das auffangen muss... Heute habe ich endlich ein wenig Zeit gefunden, das Parallax weiterzuentwickeln. Ich möchte ja das Feinscroll mit dem Grobscroll nun verbinden und das Feinscroll habe ich ja schon mit DLI´s auseinandergerissen, so daß man z.B. drei (oder wahlweise mehr) Abschnitte das Bildschirmes mit unterschiedlichen Farben und Feinscroll-Geschwindigkeit darstellen kann. Das Grobscroll habe ich jetzt mit der Displaylistmanipulation erreicht - das war wegen des hoch auflösenden Antic D Modus notwendig - nun musste ich diesen Grobscroll auch in mehrere (auf den Feinscroll abgestimmten Bereich) separieren. Das war etwas knifflig und ein kleiner Bug ist auch noch drin, funktioniert aber jetzt. Ich kann also jetzt den Grobscroll in drei unterschiedlichen Subroutinen aufrufen, die Bereiche unabhängig voneinander hinsichtlich Geschwindigkeit und Breite usw. laufen lassen. Das binde ich jetzt in die andere Routine ein und dann sollte man das Parallax schön im Feinscroll darstellen können... das mache ich als nächstes!

Hier mal ein kleines Video vom Grobscroll dreier Bereiche in unterschiedlichen Geschwindigkeiten. Wie gesagt, 4kB Bildschirm mit DL-Manipulation. Um es besser zu sehen, habe ich einen hohen Verzögerungsfaktor eingebaut!!

Gruß Peter

Anhänge:
AntwortZitat

... puh... jetzt habe ich beide Programmteile kombiniert bekommen... also den Grobscroll mit DLI-Manipulation und den Feinscroll mit drei unterschiedlichen Geschwindigkeiten und Farben im DLI. Anbei ein kleines Video. Statt der Balken kann man jetzt quasi die Landschaft am Rand generieren. Das Timing war echt knifflig... in den drei DLI´s werden die Farben und die Feinscrolls getrennt und gesetzt - abgestimmt mit der Displaylist und den entsprechenden drei Einsprüngen, die nach Balkenhöhe an der richtigen Stelle stehen müssen. Das Grobscroll musste ich separieren, 2x wird der Grobscroll in der Hauptschleife ausgeführt, einmal direkt im DLI. Die unterschiedlichen Geschwindigkeiten werden im Hauptprogramm gezählt, der schnelle oberste Bereich bekommt zusätzlich noch einen Zähler im VBI.... Ich werde den Code noch etwas optimieren, wer ihn dann hier sehen möchte und optimieren möchte... einfach bekunden! LG Peter ... ich gehe jetzt mit grillen - mein Hirn ist schon gegrillt... parallax.MOV

Anhänge:
AntwortZitat

Müsste nicht der obere Bereich am langsamsten sein? Ansonsten Top!

Viel Spaß beim Grillen! Janko

Mein 600XL ist virenfrei!

AntwortZitat

hier jetzt nochmal mit angepassten Geschwindigkeiten und einer Random-Landschaft! Irgendwo ist da noch ein Ruckeln drin... da muss ich noch Feintuning machen... Jetzt kann ich so langsam mal die Landschaft planen und dann gehts schon relativ direkt ins neue Spiel!

Gruß und einen schönen Sonntag

Peter parallax3.MOV

Anhänge:
AntwortZitat

und hier nochmal eine weitere Version... der rechte Bildschirmrand wird ständig per Random neu aufgebaut, schön flüssig läuft jetzt der Parallax, gleichzeitig habe ich statt der 4 Farben insgesamt 10 Farben benutzt. Das wird durch drei DLI´s erreicht (die auch für die Trennung des Feinscroll in drei Blöcken sorgen). Unten am Rand will ich noch etwas weiter runtergehen und mittels eines weiteren DLI wird dann später noch für die Anzeigen(Punkte, Fuel, etc.) auf einen normalen Charakterset umgeschaltet....

parallax4.MOV

Anhänge:
AntwortZitat

.... ich bin jetzt eigentlich erst einmal mit dem Thema Parallax fertig - besteht Interesse an dem Assembler-Code, oder macht das keinen Sinn, weil das nicht so wirklich oft genutzt wird? Wenn ja, dann würde ich den Code noch ein wenig aufarbeiten und mit Remarks versehen - jeder kann dann beliebig ausprobieren, ändern oder erweitern oder selbst nutzen. Es gibt da bestimmt auch ne Menge, was man noch viel effizienter programmieren kann!

Ansonsten werde ich mich jetzt sehr intensiv den Softwaresprites widmen...

Gruß Peter

AntwortZitat

Hi!

Selbst wenn Parallax-Scrolling nicht ganz so oft gebraucht wird, wäre es doch schade, wenn nun die Lösung (sprich Quelltext) hier nicht gepostet wird. Also ich würde es begrüßen, wenn Du den Quellcode hier posten würdest.

Grüße Janko

Mein 600XL ist virenfrei!

AntwortZitat

Ja, auch ich würde das gerne studieren. Also gerne mit Kommentaren hier veröffentlichten.

AntwortZitat

hier das Listing:

        org $1000


;----- Definition der Hardwareregister -----

RANDOM = 53770
XITVBV = 58466
SETVBV = 58460
VDSLST = 512
NMIEN = 54286
wsync = 54282
hscrol = 54276
rtclok = 18

colpf0 = 53270
colpf1 = 53271
colpf2 = 53272
colpf3 = 53273

;-----  Definition dere Variablen ----

screen = 220
scrolm1 = 222
scrolm2 = 223
scrolm3 = 224
scrolindex1 = 225
scrolindex2 = 226
scrolindex3 = 227
display = 228


zeilen = 230    
delay = 232
var1 = 233
var0 = 234
var80 = 236
var160 = 238    
var20 = 240
var280 = 242
var260 = 244



grob1y = 1000 
grob2y = 1001
grob3y = 1002
grobn = 1003

groba = 1004      



      .proc main

      mwa #39936 display    ;--- hier fängt die Bildschirmadresse an 0,156 = 256x156
      mwa #dlist 560      ;--- die neue Displaylist wird auf 560 umgebogen ANTIC D
      ldy #0          ;der VBI wird initialisiert
      ldx #0
      ldx #>vbinter     ;VB-Interrupt VektorHi
      ldy #<vbinter     ;VB-Interrupt VektorLo
      lda #7          ;Deferred Mode mit lda #7 festlegen
      jsr setvbv        

      lda #<dli0        ;der 1. Displaylist-Interrupt wird initialisiert  
      sta VDSLST
      lda #>dli0
      sta VDSLST+1
      lda #192
      sta NMIEN

      ldy #0
      lda #4
      sta scrolm1
      sta scrolm2
      sta scrolm3



loop                ;hier steht das Hauptprogramm



      jsr scrolling     ;der Scrollaufruf

      mva #0 delay      ;eine Warteschleife 1/50sek.
      jsr wartes


      jmp loop

      .endp



      ; ---------------------------- S U B R O U T I N E N ----------------------------------

      .proc scrolling       
      #if .byte scrolm2<=#4     ; Zähler für Feinscroll - in Antic D von 8 -> 4
      jsr grob2         ; der Grobscroll für den mittleren Bereich wird ausgeführt
      mva #8 scrolm2
      #end

      #if .byte scrolm3<=#4
      mva #8 scrolm3        ; Grobscroll unterer Bereich
      jsr grob3
      #end
                    ; hier wird die Geschwindigkeit gesteuert
      inc scrolindex1
      inc scrolindex2
      inc scrolindex3

      #if .byte scrolindex1=#3
      mva #0 scrolindex1
      dec scrolm1
      #end
      #if .byte scrolindex2=#2
      mva #0 scrolindex2
      dec scrolm2
      #end
      #if .byte scrolindex3=#1
      mva #0 scrolindex3
      dec scrolm3
      #end
      rts
      .endp
      .proc grobmain        ;diese Routine macht den Grobscroll für Grob1,2,3

@     tya
      sta dlist,x         ;hier wird die jeweilige DList pro Zeile geschoben
      lda random          
      sta (var20),y       ;Wert rechts außen speichern (sichtbar) 
      dey
      sta (var0),y        ;Wert um eins verschoben in den unsichtbaren Bereich schieben
      iny
      inx             ;3x inx für die nächste DL-Zeile
      inx
      inx
      tya
      adc #80           ;wir bearbeiten in dieser Routine immer 3 DL Zeilen
      sta dlist,x         ;0 / 80 / 160 - da sind immer 2x40 Zeilen drin - die sichtbare und die unsichtbare
      lda random          ;und nach 3 Zeilen wird einfach das High Byte incrementiert 
      sta (var280),y        ;danach startet diese Routine erneut für einen 3er Block
      dey
      sta (var80),y
      iny
      inx
      inx
      inx
      tya
      adc #160          ;3.Zeile
      sta dlist,x
      lda random
      sta (var260),y
      dey
      sta (var160),y
      iny
      inx
      inx
      inx
      inc var0+1          ;das High Byte wird für alle incrementiert
      inc var80+1
      inc var160+1
      inc var20+1
      inc var280+1
      inc var260+1

      clc
      inc zeilen          ;Anzahl der Zeilen pro Block
      #if .byte zeilen<grobn    ;es werden max.81 Zeilen grobgescrollt (dann geht x über 255)
      jmp @-
      #end
      rts
      .endp
      .proc grob1

      mva #0 zeilen
      lda #156
      sta var0+1
      sta var80+1
      sta var160+1
      sta var20+1
      sta var280+1
      sta var260+1
      mva #0 var0
      mva #80 var80
      mva #160 var160
      mva #43 var20     ;0+39
      mva #123 var280     ;80+39
      mva #203 var260     ;160+39
      mva #0 zeilen
      ;mva #0 groba
      ;#if .byte grob1y<#1
      mva random groba    ;in groba kommt rein was rechts geprintet  wird
      ;#end
      ldx #7          ;bei 7 wird die erste Displaylist manipuliert - dann immer plus 3
      mva #2 grobn      ;der erste Block ist 2x3 Zeilen breit
      ldy grob1y
      #if .byte grob1y=#48  ;wegen des DLI haben wir nicht 40 Zeichen pro Zeile sondern 48
      #end
      jsr grobmain
      inc grob1y

      #if .byte grob1y=#47
      mva #0 grob1y

      #end

      rts
      .endp
      .proc grob2

      mva #0 zeilen

      lda #158
      sta var0+1
      sta var80+1
      sta var160+1
      sta var20+1
      sta var280+1
      sta var260+1
      mva #0 var0
      mva #80 var80
      mva #160 var160
      mva #43 var20     ;0+39
      mva #123 var280     ;80+39
      mva #203 var260     ;160+39
      mva #0 zeilen
      ;mva #0 groba
      ;#if .byte grob2y<#1
      mva random groba
      ;#end
      ldx #25
      mva #4 grobn
      ldy grob2y
      #if .byte grob2y=#48
      #end
      jsr grobmain
      inc grob2y

      #if .byte grob2y=#47
      mva #0 grob2y

      #end

      rts
      .endp
      .proc grob3
      lda #162
      sta var0+1
      sta var80+1
      sta var160+1
      sta var20+1
      sta var280+1
      sta var260+1
      mva #0 var0
      mva #80 var80
      mva #160 var160
      mva #43 var20     ;0+39
      mva #123 var280     ;80+39
      mva #203 var260     ;160+39
      mva #0 zeilen
      ;mva #0 groba
      ;#if .byte grob3y<#1
      mva random groba
      ;#end
      ldx #61
      mva #21 grobn
      ldy grob3y
      #if .byte grob3y=#48
      #end
      jsr grobmain
      inc grob3y

      #if .byte grob3y=#47
      mva #0 grob3y

      #end

      rts
      .endp 
      .proc wartes
      clc
        ldx delay ; Warteschleife
st      
      lda RTCLOK+2

wa   
      cmp RTCLOK+2 
          beq wa 

          dex            
          bpl st 
          rts
        .endp   
      .proc dli0        ;Farbe mittlerer Streifen
        phr
        sta wsync

        mva #2 colpf0
        mva #6 colpf1 
        mva #10 colpf2
        mva #14 colpf3
        mva scrolm2 hscrol    ;hier wird der Feinscroll gesteuert
        #if .byte scrolm1<=#4   ;der erste Balken wird im 1.DLI gesteuert
      jsr grob1       ;der mittlere und untere im Hauptprogramm
      mva #8 scrolm1
      #end
        mwa #dli1 512     ;hier wird im 1.DLI der 2.DLI initialisiert   
        plr
        rti
      .endp
      .proc dli1        ;Farbe unterer Streifen
        phr

        mva scrolm3 hscrol    ;hier wird der Feinscroll gesteuert
        mva #37 colpf1
        mva #101 colpf0
        mva #168 colpf2
        mva #246 colpf3
        mwa #dli2 512     ;der 2. DLI initialisiert den 3.DLI

        plr
        rti
      .endp   
      .proc dli2
        phr

        mva scrolm1 hscrol    ;hier wird der Feinscroll gesteuert

        mwa #dli0 512     ;der 3.DLI initialisiert den 1.DLI

        plr
        rti
      .endp
      .proc vbinter     ;den VBI brauchen wir aktuell nur für die Farbe des ersten Blocks



      pha
      txa
      pha
      tya
      pha


      mva #222 colpf1
        mva #68 colpf0
        mva #182 colpf2
        mva #38 colpf3


      pla
      tay
      pla
      tax
      pla
      jmp xitvbv      ;vb-interrupt wird über xitvbv beendet!!

      .endp

dlist   .by 117,117,117     ;dies ist die Displaylist
    .by 93,210,155      ;keine Ahnung warum, aber diese scheinbar unnötige Zeile brauche ich hier...
    .by 93,0,156      ;hier geht die erste Zeile des ersten Blocks los
    .by 93,80,156     ;93= 64 (Sprungbefehl)+16 (HSCROL aktiv) +13 (Antic D)
    .by 93,160,156

    .by 93,0,157
    .by 93,80,157
    .by 221,160,157     ;93 +128 (Interrupt wird ausgelöst)   

    .by 93,0,158
    .by 93,80,158
    .by 93,160,158  

    .by 93,0,159
    .by 93,80,159
    .by 93,160,159  

    .by 93,0,160    
    .by 93,80,160
    .by 93,160,160

    .by 93,0,161
    .by 93,80,161
    .by 221,160,161

    .by 93,0,162
    .by 93,80,162
    .by 93,160,162

    .by 93,0,163
    .by 93,80,163
    .by 93,160,163

    .by 93,0,164    
    .by 93,80,164
    .by 93,160,164

    .by 93,0,165
    .by 93,80,165
    .by 93,160,165

    .by 93,0,166
    .by 93,80,166
    .by 93,160,166  

    .by 93,0,167
    .by 93,80,167
    .by 93,160,167

    .by 93,0,168  
    .by 93,80,168
    .by 93,160,168

    .by 93,0,169
    .by 93,80,169
    .by 93,160,169

    .by 93,0,170
    .by 93,80,170
    .by 93,160,170

    .by 93,0,171
    .by 93,80,171
    .by 93,160,171

    .by 93,0,172
    .by 93,80,172
    .by 93,160,172

    .by 93,0,173
    .by 93,80,173
    .by 93,160,173

    .by 93,0,174
    .by 93,80,174
    .by 93,160,174

    .by 93,0,175
    .by 93,80,175
    .by 93,160,175

    .by 93,0,176  
    .by 93,80,176
    .by 93,160,176

    .by 93,0,177
    .by 93,80,177
    .by 93,160,177

    .by 93,0,178
    .by 93,80,178
    .by 93,160,178

    .by 93,0,179
    .by 93,80,179
    .by 93,160,179

    .by 93,0,180  
    .by 93,80,180
    .by 93,160,180

    .by 93,0,181
    .by 93,80,181
    .by 93,160,181

    .by 93,0,182
    .by 93,80,182
    .by 93,160,182

    .by 93,0,183
    .by 93,80,183
    .by 93,160,183

    .by 93,0,184
    .by 93,80,184
    .by 93,160,184

    .by 93,0,185
    .by 93,80,185
    .by 93,160,185

    .by 93,0,186
    .by 93,80,186
    .by 93,160,186

    .by 93,0,187
    .by 93,80,187
    .by 221,160,187

    .by 65
    .wo dlist
      run main
AntwortZitat

Die PF Assembler Ecke aus der CK 10-11/86 beschäftigt sich übrigens mit DLIs. Gruß Wolfgang

AntwortZitat